package com.eight.cloud.payment.facade;

import cn.hutool.core.util.ObjectUtil;
import com.eight.cloud.core.global.exception.CustomException;
import com.eight.cloud.core.global.model.BaseUser;
import com.eight.cloud.core.utils.format.Validate;
import com.eight.cloud.core.utils.supply.UserContext;
import com.eight.cloud.client.model.dto.OrderDto;
import com.eight.cloud.client.model.dto.RefundDto;
import com.eight.cloud.payment.common.enums.PayChannelEnum;
import com.eight.cloud.payment.common.enums.PayStrategyEnum;
import com.eight.cloud.payment.common.enums.TradeTypeEnum;
import com.eight.cloud.payment.entity.SubPayOrderEntity;
import com.eight.cloud.payment.entity.SubRefundOrderEntity;
import com.eight.cloud.payment.model.dto.SubPayOrderDto;
import com.eight.cloud.payment.model.dto.SubRefundOrderDto;
import com.eight.cloud.payment.model.vo.SubPayOrderVo;
import com.eight.cloud.payment.model.vo.SubRefundOrderVo;
import com.eight.cloud.payment.service.ISubPayOrderService;
import com.eight.cloud.payment.service.ISubRefundOrderService;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * 订单外观业务类
 *
 * @ClassName: OrderFacade
 * @Author: TXC
 * @Date: 2025-01-09 11:03
 **/
@Service
public class OrderFacade {
    @Resource
    private ISubPayOrderService subPayOrderService;
    @Resource
    private ISubRefundOrderService subRefundOrderService;

    /**
     * 添加退款订单
     *
     * @param subRefundOrderDto 退款订单dto
     * @return 退款订单vo
     */
    public SubRefundOrderVo addRefundOrder(SubRefundOrderDto subRefundOrderDto) {
        SubRefundOrderVo subRefundOrder = subRefundOrderService.findSubRefundOrder(subRefundOrderDto.getMerchantId(),
                subRefundOrderDto.getSubRefundNo(), subRefundOrderDto.getAppid());
        // 判断退款订单是否存在
        if (ObjectUtil.isNotNull(subRefundOrder)) {
            if (!Objects.equals(subRefundOrder.getStatus(), SubRefundOrderEntity.RefundStatusEnum.SUCCESS.getValue())) {
                throw new RuntimeException("订单已退款");
            } else {
                if (!Objects.equals(subRefundOrderDto.getRefund(), subRefundOrder.getRefund())) {
                    throw new RuntimeException("订单退款金额不一致");
                }
                return subRefundOrder;
            }
        }
        // 获取原支付订单
        SubPayOrderVo subPayOrderVo = subPayOrderService.findSubPayOrder(subRefundOrderDto.getMerchantId(),
                subRefundOrderDto.getSubOutTradeNo(), subRefundOrderDto.getAppid());
        if (ObjectUtil.isNull(subPayOrderVo)) {
            throw new CustomException(500, "原支付订单不存在");
        }
        if (!Objects.equals(subPayOrderVo.getStatus(), SubPayOrderEntity.PayStatusEnum.PAID.getValue())) {
            throw new CustomException(500, "原支付订单未支付");
        }
        if (subPayOrderVo.getTotal() < subRefundOrderDto.getRefund()) {
            throw new CustomException(500, "退款金额不能大于原支付订单金额");
        }
        if (subPayOrderVo.getTotal() > subRefundOrderDto.getRefund()) {
            throw new CustomException(500, "退款金额不能小于原支付订单金额");
        }
        if (!subPayOrderVo.getTotal().equals(subRefundOrderDto.getTotal())) {
            throw new CustomException(500, "退款金额与原支付订单金额不一致");
        }
        subRefundOrderDto.setOutTradeNo(subPayOrderVo.getUuid());
        subRefundOrderDto.setTenantId(subPayOrderVo.getTenantId());
        subRefundOrderDto.setDeptId(subPayOrderVo.getDeptId());
        return subRefundOrderService.addOrder(subRefundOrderDto);
    }

    /**
     * 添加退款订单
     *
     * @param payStrategyEnum 支付策略枚举
     * @param refund 退款订单信息
     * @return 退款订单VO
     */
    public SubRefundOrderVo addRefundOrder(PayStrategyEnum payStrategyEnum, RefundDto refund) {
        BaseUser appUser = UserContext.getUser();
        SubRefundOrderDto subRefundOrderDto = new SubRefundOrderDto();
        subRefundOrderDto.setMerchantId(refund.getSubMerchantId());
        subRefundOrderDto.setAppid(appUser.getUuid());
        subRefundOrderDto.setTradeType(TradeTypeEnum.getByCode(payStrategyEnum.getType().getCode()));
        subRefundOrderDto.setPayChannel(PayChannelEnum.getByCode(payStrategyEnum.getChannel().getCode()));
        subRefundOrderDto.setTotal(Long.parseUnsignedLong(refund.getTotal()));
        subRefundOrderDto.setRefund(Long.parseUnsignedLong(refund.getRefund()));
        subRefundOrderDto.setSubOutTradeNo(refund.getOutTradeNo());
        subRefundOrderDto.setSubRefundNo(refund.getOutRefundNo());
        subRefundOrderDto.setSourceFrom(SubRefundOrderEntity.RefundSourceFormEnum.APP.getValue());
        Validate.checkField(ObjectUtil::isEmpty, subRefundOrderDto.getSubRefundNo(), "商户退款单号");
        return addRefundOrder(subRefundOrderDto);
    }

    /**
     * 添加支付订单
     *
     * @param payStrategyEnum 支付策略枚举
     * @param order 订单信息
     * @return 支付订单VO
     */
    public SubPayOrderVo addPayOrder(PayStrategyEnum payStrategyEnum, OrderDto order) {
        BaseUser appUser = UserContext.getUser();
        SubPayOrderDto subPayOrderDto = new SubPayOrderDto();
        subPayOrderDto.setMerchantId(order.getSubMerchantId());
        subPayOrderDto.setAppid(appUser.getUuid());
        subPayOrderDto.setTradeType(TradeTypeEnum.getByCode(payStrategyEnum.getType().getCode()));
        subPayOrderDto.setPayChannel(PayChannelEnum.getByCode(payStrategyEnum.getChannel().getCode()));
        subPayOrderDto.setTotal(Long.parseUnsignedLong(order.getPriceFen()));
        subPayOrderDto.setSubOrderId(order.getOutTradeNo());
        return subPayOrderService.addOrder(subPayOrderDto);
    }

    /**
     * 支付成功处理
     *
     * @param payOrderUuid 支付订单UUID
     * @param transactionId 支付平台交易ID
     */
    public void doSuccessPay(String payOrderUuid, String transactionId) {
        subPayOrderService.updateSubPayOrder(payOrderUuid, transactionId,
                SubPayOrderEntity.PayStatusEnum.PAID.getValue());
    }

    /**
     * 退款成功处理
     *
     * @param refundOrderUuid 退款订单UUID
     * @param transactionId 支付平台退款交易ID
     */
    public void doSuccessRefund(String refundOrderUuid, String transactionId) {
        // 获取退款订单
        SubRefundOrderEntity subRefundOrder = subRefundOrderService.getByUuid(refundOrderUuid);
        // 更新退款订单状态
        subRefundOrderService.updateSubRefundOrder(refundOrderUuid, transactionId,
                SubRefundOrderEntity.RefundStatusEnum.SUCCESS.getValue());
        // 更新支付订单状态
        subPayOrderService.updateSubPayOrder(subRefundOrder.getOutTradeNo(), null,
                SubPayOrderEntity.PayStatusEnum.REFUND.getValue());
    }

    /**
     * 退款支付订单
     *
     * @param payOrderUuid 支付订单UUID
     * @return 退款订单VO
     */
    public SubRefundOrderVo refundPayOrder(String payOrderUuid) {
        SubPayOrderEntity subPayOrder = subPayOrderService.getByUuid(payOrderUuid);
        if (ObjectUtil.isNull(subPayOrder)) {
            throw new CustomException(500, "支付订单不存在");
        }
        if (!Objects.equals(subPayOrder.getStatus(), SubPayOrderEntity.PayStatusEnum.PAID.getValue())) {
            throw new CustomException(500, "支付订单未支付");
        }
        SubRefundOrderDto subRefundOrderDto = getSubRefundOrderDto(subPayOrder);
        return addRefundOrder(subRefundOrderDto);
    }

    /**
     * 通过支付订单生成退款订单参数
     *
     * @param subPayOrder 支付订单实体
     * @return 退款订单DTO
     */
    private static @NotNull SubRefundOrderDto getSubRefundOrderDto(SubPayOrderEntity subPayOrder) {
        SubRefundOrderDto subRefundOrderDto = new SubRefundOrderDto();
        subRefundOrderDto.setMerchantId(subPayOrder.getMerchantId());
        subRefundOrderDto.setAppid(subPayOrder.getAppid());
        subRefundOrderDto.setTradeType(TradeTypeEnum.getByCode(subPayOrder.getTradeType()));
        subRefundOrderDto.setPayChannel(PayChannelEnum.getByCode(subPayOrder.getPayChannel()));
        subRefundOrderDto.setTotal(subPayOrder.getTotal());
        subRefundOrderDto.setRefund(subPayOrder.getTotal());
        subRefundOrderDto.setSubOutTradeNo(subPayOrder.getSubOrderId());
        subRefundOrderDto.setSourceFrom(SubRefundOrderEntity.RefundSourceFormEnum.PLATFORM.getValue());
        return subRefundOrderDto;
    }

}
